<?php

// ------------------------------------------------------------------------
// |@Author       : Jarmin <topextend@qq.com>
// |@----------------------------------------------------------------------
// |@Date         : 2025-05-11 01:29:54
// |@----------------------------------------------------------------------
// |@LastEditTime : 2025-05-11 14:20:03
// |@----------------------------------------------------------------------
// |@LastEditors  : Jarmin <topextend@qq.com>
// |@----------------------------------------------------------------------
// |@Description  : 加载API版本中间件
// |@----------------------------------------------------------------------
// |@FilePath     : CheckApiVersion.php
// |@----------------------------------------------------------------------
// |@Copyright (c) 2025 http://www.ladmin.cn All Rights Reserved.
// ------------------------------------------------------------------------
declare (strict_types=1);

namespace think\admin\middleware;

use Closure;
use think\Request;
use think\Response;
use think\admin\traits\ErrorCodeTrait;
use think\admin\service\ApiVersionService;
use think\admin\exception\BusinessException;

/**
 * 加载API版本中间件
 * Class LoadApiVersion
 * @package think\admin\middleware
 */
class CheckApiVersion
{
    use ErrorCodeTrait;

    /**
     * @var ApiVersionService
     */
    protected $apiVersionService;

    /**
     * 构造函数
     * @access public
     * @param ApiVersionService $apiVersionService
     */
    public function __construct(ApiVersionService $apiVersionService)
    {
        $this->apiVersionService = $apiVersionService;
    }

    /**
     * 处理请求
     * @access public
     * @param Request $request
     * @param Closure $next
     * @return Response
     */
    public function handle(Request $request, Closure $next): Response
    {
        try {
            // 获取当前请求的路径和方法
            $path = $request->pathinfo();
            $method = $request->method();
            // 从缓存获取接口信息
            $interface = $this->getInterfaceInfo($path, $method);
            // 如果接口不存在，返回错误响应
            if (!$interface) {
                throw new BusinessException('接口不存在');
            }
            // 检查接口状态
            if ($interface['status'] != 1) {
                throw new BusinessException('接口已禁用');
            }
            // 使用API_VERSION常量
            $version = API_VERSION;
            // 检查版本是否在支持范围内
            if (!$this->checkVersionRange($version, $interface['min_version'], $interface['max_version'])) {
                throw new BusinessException('不支持的API版本');
            }
            // 检查版本状态
            $versionInfo = $this->getVersionInfo($version);
            // 如果版本信息不存在，返回错误响应
            if (!$versionInfo) {
                throw new BusinessException('API版本不存在');
            }
            // 检查版本是否过期
            if ($this->isVersionExpired($versionInfo)) {
                throw new BusinessException('API版本已过期');
            }
            // 检查是否需要强制升级
            if ($this->needForceUpgrade($versionInfo)) {
                $errorData = [
                    'current_version' => $version,
                    'target_version' => $interface['current_version'],
                    'upgrade_guide' => [
                        'header' => 'X-Api-Version',
                        'value' => $interface['current_version']
                    ],
                    'upgrade_guide_url' => $versionInfo['upgrade_guide_url'],
                    'notice' => '当前版本即将停止支持，请升级到新版本'
                ];
                throw new BusinessException('需要升级到新版本', self::BUSINESS_ERROR, $errorData);
            }
            // 检查是否需要警告升级
            if ($this->needWarningUpgrade($versionInfo)) {
                $response = $next($request);
                if (method_exists($response, 'header')) {
                    $response->header([
                        'X-API-Version-Warning' => 'true',
                        'X-API-Current-Version' => $version,
                        'X-API-Target-Version' => $interface['current_version'],
                        'X-API-Upgrade-Guide-URL' => $versionInfo['upgrade_guide_url']
                    ]);
                }
                return $response;
            }
            // 检查灰度发布
            $targetVersion = $this->checkGrayRelease($version, $request);
            // 如果是灰度版本，在响应头中返回新版本信息
            if ($targetVersion && $targetVersion !== $version) {
                $response = $next($request);
                if (method_exists($response, 'header')) {
                    $response->header([
                        'X-API-Version' => $targetVersion,
                        'X-API-Upgrade' => 'available',
                        'X-API-Upgrade-Guide-URL' => $versionInfo['upgrade_guide_url']
                    ]);
                }
                return $response;
            }

            return $next($request);
        } catch (\Exception $e) {
            return json([
                'code' => $e->getCode() ?: 400,
                'message' => $e->getMessage(),
                'data' => $e->getErrorData(),
                'timestamp' => time()
            ]);
        }
    }

    /**
     * 从缓存获取接口信息
     */
    public function getInterfaceInfo($path, $method)
    {
        return $this->apiVersionService->getInterfaceInfo($path, $method);
    }

    /**
     * 检查版本范围
     */
    protected function checkVersionRange($version, $minVersion, $maxVersion)
    {
        return version_compare($version, $minVersion, '>=') && version_compare($version, $maxVersion, '<=');
    }

    /**
     * 获取版本信息
     */
    protected function getVersionInfo($version)
    {
        return $this->apiVersionService->getVersionInfo($version);
    }

    /**
     * 检查版本是否过期
     */
    protected function isVersionExpired($versionInfo)
    {
        return $versionInfo['status'] != 1 || strtotime($versionInfo['expire_at']) < time();
    }

    /**
     * 检查是否需要强制升级
     */
    protected function needForceUpgrade($versionInfo)
    {
        $days = (strtotime($versionInfo['end_of_life']) - time()) / 86400;
        return $days <= $versionInfo['force_upgrade_days'];
    }

    /**
     * 检查是否需要警告升级
     */
    protected function needWarningUpgrade($versionInfo)
    {
        $days = (strtotime($versionInfo['end_of_life']) - time()) / 86400;
        return $days <= $versionInfo['warning_days'];
    }

    /**
     * 检查灰度发布
     */
    protected function checkGrayRelease($version, $request)
    {
        return $this->apiVersionService->checkGrayRelease($version, $request);
    }
}
